﻿#include "../../../includes/multimedia/rtsp/h264source.h"
#include "../../../includes/multimedia/rtsp/crtspclient.h"
#include "../../../includes/multimedia/rtsp/crtsppusher.h"

#include <cstdio>
#include <chrono>
#if defined(__linux) || defined(__linux__)
#include <sys/time.h>
#endif

H264Source::H264Source(unsigned int framerate)
    : framerate_(framerate),
      mRtspClient(NULL)
{
    payload_    = 96;
    media_type_ = H264;
    clock_rate_ = 90000;
}

H264Source::~H264Source()
{

}

std::string H264Source::GetMediaDescription(unsigned short port)
{
    char buf[100] = {0};
    sprintf(buf, "m=video %hu RTP/AVP 96", port);
    return buf;
}

const char* H264Source::GetAttribute()
{
    return "a=rtpmap:96 H264/90000";
}

unsigned int H264Source::GetTimestamp()
{
    auto time_point = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::steady_clock::now());
    return (unsigned int)((time_point.time_since_epoch().count() + 500) / 1000 * 90 );
}

bool H264Source::HandleFrame(AVFrame *frame)
{
    if(frame == NULL) return false;

    uint8_t* frame_buf  = (uint8_t*)frame->buffer.get();
    uint32_t frame_size = frame->size;
    qint64 size = 0;

    if (frame->timestamp == 0) {
        frame->timestamp = GetTimestamp();
    }

    if (frame_size <= MAX_RTP_PAYLOAD_SIZE) {
        RtpPacket rtp_pkt;
        rtp_pkt.type = frame->type;
        rtp_pkt.timestamp = frame->timestamp;
        rtp_pkt.size = frame_size + RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE;
        rtp_pkt.last = 1;
        memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE, frame_buf, frame_size);

        if(mRtspClient != NULL)
            size = mRtspClient->sendUdpData(&rtp_pkt);
        else if(mRtspPusher != NULL)
            size = mRtspPusher->sendPacketData(&rtp_pkt);
    }
    else {
        char FU_A[2] = {0};

        FU_A[0] = (frame_buf[0] & 0xE0) | 28;
        FU_A[1] = 0x80 | (frame_buf[0] & 0x1f);

        frame_buf  += 1;
        frame_size -= 1;

        while (frame_size + 2 > MAX_RTP_PAYLOAD_SIZE) {
            RtpPacket rtp_pkt;
            rtp_pkt.type = frame->type;
            rtp_pkt.timestamp = frame->timestamp;
            rtp_pkt.size = RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + MAX_RTP_PAYLOAD_SIZE;
            rtp_pkt.last = 0;

            rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 0] = FU_A[0];
            rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = FU_A[1];
            memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+2, frame_buf, MAX_RTP_PAYLOAD_SIZE-2);

            if(mRtspClient != NULL)
                size = mRtspClient->sendUdpData(&rtp_pkt);
            else if(mRtspPusher != NULL)
                size = mRtspPusher->sendPacketData(&rtp_pkt);

            frame_buf  += MAX_RTP_PAYLOAD_SIZE - 2;
            frame_size -= MAX_RTP_PAYLOAD_SIZE - 2;

            FU_A[1] &= ~0x80;
        }

        {
            RtpPacket rtp_pkt;
            rtp_pkt.type = frame->type;
            rtp_pkt.timestamp = frame->timestamp;
            rtp_pkt.size = 4 + RTP_HEADER_SIZE + 2 + frame_size;
            rtp_pkt.last = 1;

            FU_A[1] |= 0x40;
            rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 0] = FU_A[0];
            rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = FU_A[1];
            memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+2, frame_buf, frame_size);

            if(mRtspClient != NULL)
                size = mRtspClient->sendUdpData(&rtp_pkt);
            else if(mRtspPusher != NULL)
                size = mRtspPusher->sendPacketData(&rtp_pkt);
        }
    }

    return true;
}
